import { ItemUseAfterEvent, world } from "@minecraft/server";
import { consumeDurability, setEquipmentItem } from "../../../utils";

/**
 * A simple prop *(an item that can be used)* , can only be used once.
 */
export class Prop {
  constructor(
    /**
     * Identifier of the type of items for the stack. If a namespace is not specified, 'minecraft:' is assumed.
     */
    readonly typeId: string,
    /**
     * The event when an item is successfully used by a player.
     */
    public useEvent?: (arg: ItemUseAfterEvent) => void,
  ) {
    this.register();
  }
  /**
   * Registry the prop.
   */
  protected register() {
    world.afterEvents.itemUse.subscribe((event) => {
      if (event.itemStack.typeId === this.typeId && this.useEvent) {
        this.useEvent(event);
        setEquipmentItem(event.source);
      }
    });
  }
}

/**
 * A prop *(an item that can be used)* , Its durability is consumed after use.
 */
export class DurabilityLimitedProp extends Prop {
  constructor(
    /**
     * Identifier of the type of items for the stack. If a namespace is not specified, 'minecraft:' is assumed.
     */
    readonly typeId: string,
    /**
     * The durability to be consumed.
     */
    public durabilityValue: number,
  ) {
    super(typeId);
    this.register();
  }
  /**
   * Registry the prop.
   */
  protected register() {
    world.afterEvents.itemUse.subscribe((event) => {
      if (event.itemStack.typeId === this.typeId && this.useEvent) {
        this.useEvent(event);
        setEquipmentItem(
          event.source,
          consumeDurability(
            event.itemStack,
            this.durabilityValue,
            event.source,
          ),
        );
      }
    });
  }
}

/**
 * A prop *(an item that can be used)* , it has a limited number of uses.
 */
export class NumberLimitedProp extends Prop {
  constructor(
    /**
     * Identifier of the type of items for the stack. If a namespace is not specified, 'minecraft:' is assumed.
     */
    readonly typeId: string,
    /**
     * Options of the prop.
     */
    public options: NumberLimitedPropOptions,
  ) {
    super(typeId);
    this.register();
  }
  /**
   * Registry the prop.
   */
  protected register() {
    let [MAX_USE, ONCE_CONS] = [this.options.maxUse, this.options.onceConsumed];
    if (!ONCE_CONS) ONCE_CONS = 1;
    world.afterEvents.itemUse.subscribe((event) => {
      if (event.itemStack.typeId === this.typeId && this.useEvent) {
        const [PLAYER, ITEM] = [event.source, event.itemStack];
        const VALUE = ITEM.getDynamicProperty("lazuli:use_value") as number;
        this.useEvent(event);
        if (VALUE) {
          ITEM.setDynamicProperty("lazuli:use_value", VALUE + ONCE_CONS);
        } else {
          ITEM.setDynamicProperty("lazuli:use_value", ONCE_CONS);
        }
        if (VALUE > MAX_USE) {
          setEquipmentItem(PLAYER);
        }
      }
    });
  }
}

/**
 * Options of the prop.
 */
export interface NumberLimitedPropOptions {
  /**
   * The maximum use value of the item.
   */
  maxUse: number;
  /**
   *  Consumed use value when use the item, default is `1`.
   */
  onceConsumed?: number;
}
